1 /*
2 * Title: S/MIME Project
3 * Description: S/MIME email sending capabilities
4 * @Author Vladimir Radisic
5 * @Version 2.0.1
6 */
7
8 package org.webdocwf.util.smime.util;
9
10
11 import java.security.KeyStore;
12 import java.security.Signature;
13 import java.security.PrivateKey;
14 import java.security.cert.X509Certificate;
15 import java.util.Vector;
16 import java.util.Enumeration;
17 import org.webdocwf.util.smime.exception.SMIMEException;
18 import org.webdocwf.util.smime.exception.ErrorStorage;
19 import org.bouncycastle.jce.provider.JDKDigestSignature;
20
21 import java.security.cert.Certificate;
22
23
24 /***
25 * PFXUtils class has static methods which are dealing with .pfx, or .p12
26 * files. The file (of this types) presents storage for keeping certificate
27 * chain and private key. Information from this files are being transported
28 * through programs via instance of the Java class KeyStore.
29 */
30 public class PFXUtils {
31
32 /***
33 * Returns the owner's Certificate from his .pfx or .p12 file (KeyStore)
34 * @param ks0 container for information from .pfx or .p12 file
35 * @return Owner's Certificate
36 * @exception SMIMEException if problem with extracting certificate
37 * chain from .pfx or .p12 file or with aliases in pfx or p12 file arrises.
38 * Also, it can be caused by non SMIMEException which is KeyStoreException.
39 */
40 public static X509Certificate getPFXOwnerX509Certificate(KeyStore ks0) throws SMIMEException {
41 X509Certificate[] certChain = PFXUtils.getCertificateChain(ks0);
42
43 if (certChain != null)
44 return certChain[0];
45
46 return PFXUtils.getAllX509Certificate(ks0)[0];
47 }
48
49 /***
50 * Returns the Private key of the certificate's owner from .pfx or .p12
51 * file (pkcs12 format)
52 * @param ks0 container for information from .pfx or .p12 file
53 * @return Owners private key
54 * @exception SMIMEException caused by non SMIMEException which can be one of
55 * the following: KeyStoreException, UnrecoverableKeyException or
56 * NoSuchAlgorithmException.
57 */
58 public static PrivateKey getPrivateKey(KeyStore ks0) throws SMIMEException {
59 String keyAlias = null; // Alias for public key certificate corresponding to private key
60 PrivateKey returnPrivateKey = null;
61
62 try {
63 Enumeration en = ks0.aliases();
64
65 while (en.hasMoreElements()) {
66 String temp = (String) en.nextElement();
67
68 if (ks0.isKeyEntry(temp))
69 keyAlias = temp;
70 }
71 returnPrivateKey = (PrivateKey) ks0.getKey(keyAlias, null); // Obtaining private key as PrivateKey class
72 } catch (Exception e) {
73 throw SMIMEException.getInstance("org.webdocwf.util.smime.util.PFXUtils",
74 e, "getPrivateKey");
75 }
76 return returnPrivateKey;
77 }
78
79 /***
80 * Returns all X509 Certificates stored in .pfx, or .p12 files
81 * (KeyStore). This method performs same task as method getCertificateChain() but
82 * on less elegant way. In the future project version, it will be completely
83 * replaced with the getCertificateChain() method.
84 * @param ks0 container for information from .pfx or .p12 file
85 * @return Certificate chain represented as array of X509Certificate objects
86 * with the owner's certificate at the first place.
87 * @exception SMIMEException if problem with extracting certificate
88 * chain from .pfx or .p12 file or with aliases in pfx or p12 file arrises.
89 * Also, it can be caused by non SMIMEException which is KeyStoreException.
90 */
91 public static X509Certificate[] getAllX509Certificate(KeyStore ks0) throws SMIMEException {
92
93 Vector v = new Vector(0, 1); // Collection of certificates from pfx file
94 String certAlias = null; // Alias for public key certificate corresponding to certificate
95 X509Certificate keyEntryCert = null;
96 int numberOfAlias = 0;
97 int numberOfCert = 0;
98 int numberOfKeyEntry = 0;
99
100 try {
101 Enumeration en = ks0.aliases();
102
103 while (en.hasMoreElements()) {
104 String temp = (String) en.nextElement();
105
106 numberOfAlias++;
107 if (ks0.isKeyEntry(temp)) { // owner
108 numberOfKeyEntry++;
109 keyEntryCert = (X509Certificate) ks0.getCertificate(temp);
110 }
111 if (ks0.isCertificateEntry(temp)) {
112 X509Certificate cerCert;
113
114 cerCert = (X509Certificate) ks0.getCertificate(temp); // Getting certificate
115 v.add(cerCert);
116 numberOfCert++;
117 }
118 }
119 if ((numberOfAlias == numberOfCert + numberOfKeyEntry) & (numberOfKeyEntry == 1)) {
120 if (keyEntryCert != null) {
121 v.add(0, keyEntryCert); // is owners certificate is asociated with "key entry" alias
122 }
123 } else
124 throw new SMIMEException("org.webdocwf.util.smime.util.PFXUtils", 1037);
125 } catch (Exception e) {
126 throw SMIMEException.getInstance("org.webdocwf.util.smime.util.PFXUtils",
127 e, "getAllX509Certificate");
128 }
129 if (v.size() != 1)
130 v = getOwnersCertOnTop(v);
131 X509Certificate[] certChain = new X509Certificate[v.size()];
132
133 for (int i = 0; i != v.size(); i++)
134 certChain[i] = (X509Certificate) v.elementAt(i);
135 return certChain;
136 }
137
138 /***
139 * Returns all X509 Certificates stored in .pfx, or .p12 files (KeyStore). This
140 * method performs same task as method getAllX509Certificate() but on more elegant
141 * way.
142 * @param ks0 container for information from .pfx or .p12 file
143 * @return Certificate chain represented as array of X509Certificate objects
144 * with the owner's certificate at the first place.
145 * @exception SMIMEException caused by non SMIMEException which is
146 * KeyStoreException.
147 */
148 public static X509Certificate[] getCertificateChain(KeyStore ks0) throws SMIMEException {
149
150 boolean errorInChainReading = true;
151 int numberOfCert = 0;
152 Certificate[] certChain = new Certificate[0];
153
154 try {
155 Enumeration en = ks0.aliases();
156
157 while (en.hasMoreElements()) {
158 try {
159 String tempAlias = (String) en.nextElement();
160 Certificate[] tempCertChain = (Certificate[]) ks0.getCertificateChain(tempAlias);
161
162 if (tempCertChain != null && tempCertChain.length == certChain.length) {
163 errorInChainReading = true;
164 }
165 if (tempCertChain != null && tempCertChain.length > certChain.length) {
166 errorInChainReading = false;
167 certChain = tempCertChain;
168 }
169 if (ks0.isCertificateEntry(tempAlias))
170 numberOfCert++;
171 } catch (Exception e) {
172 continue;
173 }
174 }
175 } catch (Exception e) {
176 throw SMIMEException.getInstance("org.webdocwf.util.smime.util.PFXUtils",
177 e, "getCertificateChain");
178 }
179
180 if (certChain == null || certChain.length == 0 || errorInChainReading ||
181 certChain.length != numberOfCert)
182 return null;
183 else {
184 X509Certificate[] returnCertChain = new X509Certificate[certChain.length];
185
186 for (int i = 0; i != certChain.length; i++) {
187 returnCertChain[i] = (X509Certificate) certChain[i];
188 }
189 return returnCertChain;
190 }
191
192 }
193
194 /***
195 * Orders certificates in certificate chain with owner's certificate at the
196 * first position, in Vector representation, and root CA at the last position.
197 * @param v0 all certificates from .pfx or .p12 file
198 * @return Ordered certificates in Vector. Starts from owner's certificate (at
199 * first position) and ends with root CA certificate (at last position).
200 * @exception SMIMEException if problem with extracting certificate
201 * chain from .pfx or .p12 file arrises.
202 */
203 private static Vector getOwnersCertOnTop(Vector v0) throws SMIMEException {
204 Vector inOrder = new Vector(0, 1); // Storage for certificate chain
205 boolean ver = false;
206 int j = 0;
207
208 while (inOrder.size() == 0) {
209 if (j == v0.size())
210 throw new SMIMEException("org.webdocwf.util.smime.util.PFXUtils", 1038);
211 for (int i = 0; i != v0.size(); i++) {
212 if (i != j) {
213 ver = verification((X509Certificate) v0.elementAt(j), (X509Certificate) v0.elementAt(i));
214 if (ver) {
215 inOrder.add(v0.elementAt(j));
216 inOrder.add(v0.elementAt(i));
217 if (i > j) {
218 v0.removeElementAt(i);
219 v0.removeElementAt(j);
220 } else {
221 v0.removeElementAt(j);
222 v0.removeElementAt(i);
223 }
224 break;
225 }
226 }
227 }
228 if (ver)
229 break;
230 j++;
231 }
232 j = 0;
233 int lenBefore = v0.size();
234
235 while (v0.size() != 0) {
236 if (j > lenBefore)
237 throw new SMIMEException("org.webdocwf.util.smime.util.PFXUtils", 1038);
238 for (int i = 0; i != v0.size(); i++) {
239 ver = verification((X509Certificate) v0.elementAt(i), (X509Certificate) inOrder.firstElement());
240 if (ver) {
241 inOrder.add(0, v0.elementAt(i));
242 v0.removeElementAt(i);
243 break;
244 }
245 ver = verification((X509Certificate) inOrder.lastElement(), (X509Certificate) v0.elementAt(i));
246 if (ver) {
247 inOrder.add(v0.elementAt(i));
248 v0.removeElementAt(i);
249 break;
250 }
251 }
252 j++;
253 }
254 return inOrder;
255 }
256
257 /***
258 * Checks the relations between two certificates: if one of them is signer
259 * of another one.
260 * @param cerOwner certificate for check
261 * @param cerIssuer certificate for check
262 * @return true or false information about signing informatin between certificates
263 */
264 private static boolean verification(X509Certificate cerOwner, X509Certificate cerIssuer) {
265 boolean ret = false;
266
267 try {
268 if (cerOwner.getSigAlgOID().equalsIgnoreCase("1.2.840.113549.1.1.5")) {
269 JDKDigestSignature.SHA1WithRSAEncryption jd = new JDKDigestSignature.SHA1WithRSAEncryption();
270
271 jd.initVerify(cerIssuer.getPublicKey());
272 jd.update(cerOwner.getTBSCertificate());
273 ret = jd.verify(cerOwner.getSignature());
274 } else if (cerOwner.getSigAlgOID().equalsIgnoreCase("1.2.840.10040.4.3")) {
275 Signature sig = Signature.getInstance("SHA1withDSA", "SUN");
276
277 sig.initVerify(cerIssuer.getPublicKey());
278 sig.update(cerOwner.getTBSCertificate());
279 ret = sig.verify(cerOwner.getSignature());
280 } else if (cerOwner.getSigAlgOID().equalsIgnoreCase("1.2.840.113549.1.1.2")) {
281 JDKDigestSignature.MD2WithRSAEncryption jd = new JDKDigestSignature.MD2WithRSAEncryption();
282
283 jd.initVerify(cerIssuer.getPublicKey());
284 jd.update(cerOwner.getTBSCertificate());
285 ret = jd.verify(cerOwner.getSignature());
286 } else if (cerOwner.getSigAlgOID().equalsIgnoreCase("1.2.840.113549.1.1.4")) {
287 JDKDigestSignature.MD5WithRSAEncryption jd = new JDKDigestSignature.MD5WithRSAEncryption();
288
289 jd.initVerify(cerIssuer.getPublicKey());
290 jd.update(cerOwner.getTBSCertificate());
291 ret = jd.verify(cerOwner.getSignature());
292 }
293 } catch (Exception e) {
294 ret = false;
295 }
296 return ret;
297 }
298
299 }
300
This page was automatically generated by Maven